import Cookie from 'js-cookie';
import {simpleGet} from '../simpleGet';
import {simpleSet} from '../simpleSet';
import {ua} from '../mobile/ua';
import Fingerprint2 from 'fingerprintjs2';
import {getDeviceString} from '../mobile/device';
import murmur from '../mobile/murmurHash3';
import {syncToLocalStorage,EmptyResult,syncToServer} from './syncServer';
import safeStringify from "../safeStringify";
import map from "lodash/map";

const Version='1.0.0';
let finger=null;
const getDeviceFinger=(cb)=>{
    if(finger){
        cb(finger);
        return;
    }
    new Fingerprint2({
        excludeFlashFonts:true,
        excludeJsFonts:true,
    }).get((_finger)=>{
        finger=_finger;
        cb(finger)
    });
};

const PType={
    None:-1,
    Page:1,
    Resource:2,
    Paint:3,
    Tag:4,
};
const getDefaultItem=()=>{
    return {
        p_type:PType.None,
        name:'',
        start_time:-1,
        type:'',
        initiator_type:'',
        duration:-1,
        redirect:-1,
        fetch_start:-1,
        dns:-1,
        tcp_connect:-1,
        secure_connect:-1,
        request:-1,
        response:-1,
        transfer_size:-1,
        encode_body_size:-1,
        decode_body_size:-1,

        unload_event:-1,
        dom_loading:-1,
        dom_interactive:-1,
        dom_content_loaded:-1,
        dom_complete:-1,
        load_event:-1,

        data:''
    }
};

const PerformanceGlobalData={
    global:{

    },
    template:Object.keys(getDefaultItem()),
    data:[],
    tags:[]
};

const getInt=(obj,path,defVal)=>{
    return parseInt(simpleGet(obj,path,defVal));
};

const g=PerformanceGlobalData;
const p=window.performance;

export const initGlobalData=()=>{
    const cookie=Cookie.get()||{};

    const os=ua.getOS();
    const browser=ua.getBrowser();
    const device=ua.getDevice();

    const data={
        url:location.href||'',
        cookie:cookie.uuid||'',
        tags:g.tags.join(','),
        user_agent:navigator.userAgent||'',
        version:'',
        client:getDeviceString(),//设备字符串
        device_finger:'',
        uuid:cookie.uuid||'',
        hash:'',

        os:'',
        os_version:`${os.name} ${os.version}`,//os版本号
        device:`${device.model} ${device.vendor}`,//设备型号
        browser:`${browser.name} ${browser.version}`,//浏览器name+版本

        time_origin:getInt(p,'timeOrigin',-1),//开始时间戳
        navigation_start:getInt(p,'timing.navigationStart',-1),//开始导航时间戳
    };

    return data;
};
export const getGlobalData=()=>{
    return Object.assign({},g.global);
};

const getPageHash=({
    url='',
    tags,
    user_agent,
    device_finger,
    time_origin
}={})=>{
    const str=[url,tags,document.cookie,user_agent,device_finger,time_origin].join('@');
    return murmur.x64.hash128(str,31);
};

export const setGlobalData=(data={})=>{
    Object.assign(g.global,data);
};

const sub=(obj={},key1,key2)=>{
    const val1=obj[key1]||0;
    const val2=obj[key2]||0;
    return parseInt(val1)-parseInt(val2);
};

const defaultItem=getDefaultItem();

const fixItemData=(item)=>{
    const rst={};
    let val;
    for(let key in defaultItem){
        val=item[key];
        if(val===undefined||val===null){
            rst[key]=defaultItem[key];
            continue;
        }
        if(typeof val==='number'){
            val=parseInt(val);
        }
        rst[key]=val;
    }
    return rst;
};

const getNormalItem=(item)=>{
    return {
        name:item.name,

        type:item.entryType,
        initiator_type:item.initiatorType,
        duration:item.duration,
        redirect:sub(item,'redirectEnd','redirectStart'),
        fetch_start:p.timeOrigin+item.fetchStart,
        dns:sub(item,'domainLookupEnd','domainLookupStart'),
        tcp_connect:sub(item,'connectEnd','connectStart'),
        secure_connect:sub(item,'connectEnd','secureConnectionStart'),
        request:sub(item,'responseStart','requestStart'),
        response:sub(item,'responseEnd','responseStart'),
        transfer_size:item.transferSize,
        encode_body_size:item.encodedBodySize,
        decode_body_size:item.decodedBodySize
    }
};

const getPageItem=(item={})=>{
    const timing=p.timing;
    return {
        p_type:PType.Page,
        start_time:p.timeOrigin,

        ...getNormalItem(item),

        unload_event:sub(item,'unloadEventEnd','unloadEventStart'),
        dom_loading:timing.domLoading||-1,
        dom_interactive:sub(item,'domInteractive','domLoading'),
        dom_content_loaded:sub(item,'domContentLoadedEventEnd','domContentLoadedEventStart'),
        dom_complete:timing.domComplete||-1,
        load_event:sub(item,'loadEventEnd','loadEventStart'),
    };
};
const getResourceItem=(item)=>{
    return {
        p_type:PType.Resource,
        start_time:p.timeOrigin+item.startTime,

        ...getNormalItem(item)
    };
};
const getPaintItem=(item)=>{
    return {
        p_type:PType.Paint,
        name:item.name,
        start_time:p.timeOrigin+item.startTime,

        type:item.entryType,
        duration:item.duration
    };
};
//todo:kule 暂不实现
const getTagItem=(item)=>{
    return {
        p_type:PType.Tag,
        name:item.name,
        start_time:item.startTime,

        type:item.type,
        duration:item.duration,
        data:item.data
    };
};

const getItem=(entry)=>{
    const {entryType=''}=entry;
    if(entryType==='navigation'){
        return getPageItem(entry);
    }
    if(entryType==='resource'){
        return getResourceItem(entry);
    }
    if(entryType==='paint'){
        return getPaintItem(entry);
    }
};


const clearEntries=()=>{
    if(!performance.clearResourceTimings){
        return;
    }
    performance.clearResourceTimings();
};
const getEntries=()=>{
    if(!performance.getEntries){
        return [];
    }
    return performance.getEntries();
};
//todo:kule 添加iphone下的polyfill
const getEntriesByType=(type='resource')=>{
    if(!performance.getEntriesByType){
        return [];
    }
    return performance.getEntriesByType(type);
};
const entriesToItem=(entries)=>{
    const rst=[];
    for(let i=0;i<entries.length;i++){
        rst.push(fixItemData(getItem(entries[i])));
    }
    return rst;
};

//todo:kule 后期添加去重,防止clean不干净
let firstRecord=true;
const cleanAndRecord=()=>{
    const data=g.data;
    let newData=[];
    if(firstRecord) {
        newData=getEntries();
        firstRecord=false;
    }else{
        newData=getEntriesByType();
    }
    g.data=data.concat(entriesToItem(newData));
    clearEntries();
};
const cleanData=()=>{
    console.log('cleanData:',g.data.length);
    g.data=[];
};

const _getServerData=()=>{
    const value=map(g.data,(item)=>{
        return map(g.template,(key)=>{
            return item[key];
        });
    });
    return {
        global:g.global,
        data:{
            template:g.template,
            value
        }
    };
};
const getServerData=(getRequestArgs)=>{
    if((!firstRecord)&&(g.data.length<1)){
        return EmptyResult;
    }
    const requestArgs={
        url:'http://uc.maodou.com/prm',
        method:'post',
        postType:'json'
    };
    return {
        requestArgs:getRequestArgs(),
        // data:safeStringify(_getServerData())
        data:_getServerData()
    }
};
const _getRequestArgs=()=>{
    return {
        url:'http://uc.maodou.com/prm',
        method:'post',
        postType:'json'
    };
};

//todo:kule 暂不支持单页面应用，后期添加
export const init=({
    getVersion=()=>'',
    done,
    getRequestArgs=_getRequestArgs
}={})=>{
    setGlobalData(initGlobalData());
    getDeviceFinger((finger)=>{
        setGlobalData({
            'device_finger':finger,
        });
        setGlobalData({
            'hash':getPageHash(getGlobalData()),
            'version':getVersion()
        });
        done&&done(g);
        //todo:kule暂不考虑失败情况
        syncToLocalStorage({
            version:Version,
            key:'performance_statistic',
            getData(){
                const data=getServerData(getRequestArgs);
                cleanData();
                return data;
            },
            checkConcat(data,oldData){
                const hash=simpleGet(data,'data.global.hash');
                const oldHash=simpleGet(oldData,'data.global.hash');
                return hash===oldHash;
            },
            concatData(data,oldData){
                const value=simpleGet(data,'data.data.value',[]);
                const oldValue=simpleGet(oldData,'data.data.value',[]);
                simpleSet(data,'data.data.value',oldValue.concat(value));
                return data;
            }
        });
        syncToServer({
            version:Version,
            cleanOldVersion:true,
            key:'performance_statistic',
            interval:7000
        });
    });
    let recordHandler=setInterval(()=>{
        cleanAndRecord();
    },5000);

    const cancel=()=>{
        clearInterval(recordHandler);
    };

    return {
        cancel
    }
};